package cn.mengfly.testnrz.im.server;

import cn.mengfly.testnrz.im.client.bean.User;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import lombok.Data;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Data
public class ServerSession {

    public static final AttributeKey<String> KEY_USER_ID = AttributeKey.valueOf("key_user_id");

    public static final AttributeKey<ServerSession> SESSION_KEY = AttributeKey.valueOf("SESSION_KEY");

    private Channel channel;
    private User user;

    private final String sessionId;
    private boolean isLogin = false;

    /**
     * session中存储的session变量属性值
     */
    private Map<String, Object> map = new HashMap<>();

    public ServerSession(Channel channel) {
        this.channel = channel;
        this.sessionId = buildNewSessionId();
    }

    // 反向导航
    public static ServerSession getSession(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        return channel.attr(ServerSession.SESSION_KEY).get();
    }

    public static void closeSession(ChannelHandlerContext ctx) {
        ServerSession serverSession = ctx.channel().attr(SESSION_KEY).get();
        if (null != serverSession && serverSession.isValid()) {
            serverSession.close();
            SessionMap.inst().removeSession(serverSession.getSessionId());
        }
    }

    /**
     * 绑定会话
     *
     * @return session
     */
    public ServerSession bind() {
        System.out.println("绑定会话" + channel.remoteAddress());
        channel.attr(SESSION_KEY).set(this);
        SessionMap.inst().addSession(this);
        isLogin = true;
        return this;
    }

    public ServerSession unbind() {
        isLogin = false;
        SessionMap.inst().removeSession(getSessionId());
        this.close();
        return this;
    }

    public synchronized void set(String key, Object value) {
        map.put(key, value);
    }

    public synchronized <T> T get(String key) {
        return (T) map.get(key);
    }

    public boolean isValid() {
        return getUser() != null;
    }

    public synchronized void writeAndFlush(Object pkg) {
        channel.writeAndFlush(pkg);
    }

    public synchronized void close() {
        ChannelFuture future = channel.close();
        future.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                if (!future.isSuccess()) {
                    System.out.println("Channel Close error");
                }
            }
        });
    }

    public void setUser(User user) {
        this.user = user;
        user.setSessionId(sessionId);
    }

    private String buildNewSessionId() {
        String uuid = UUID.randomUUID().toString();
        return uuid.replaceAll("-", "");
    }
}
